home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer Power Tools
/
Programmer Power Tools.iso
/
c
/
u16pc.arc
/
U16.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-12-08
|
13KB
|
503 lines
/* This is an adaptation of the decompress part of the widespread net
* "compress" program. It is specifically designed for the IBM PC and
* clones and probably has to be compiled with the Microsoft C
* compiler (quick C won't do, it doesn't support the "huge" model).
*
* Parts written (other parts plagarized) by Tom Horsley
* (tahorsley@ssd.harris.com)
* Dec 1988.
*/
#include <stdio.h>
#include <fcntl.h>
#include <malloc.h>
/* Magic number stored in first two bytes.
*/
unsigned char magic_header[] = { "\037\235" }; /* 1F 9D */
/* Defines for third byte of header */
#define BIT_MASK 0x1f /* Max number of bits in codes */
#define BLOCK_MASK 0x80 /* This bit set if should recognize CLEAR code */
/* Space to use for input file buffer.
*/
#define MAXBUF 4096
/* a codebuf struct is used to interface with the xcode() routine.
*/
struct codebuf {
void (*codep)();
unsigned char * bufp;
} cb;
/* a codesize struct is used for advancing from one size code to
* the next.
*/
struct codesize {
void (*initp)(struct codebuf *);
int n_bits;
long int maxcode;
void (*origp)();
};
extern void init9(struct codebuf *);
extern void init10(struct codebuf *);
extern void init11(struct codebuf *);
extern void init12(struct codebuf *);
extern void init13(struct codebuf *);
extern void init14(struct codebuf *);
extern void init15(struct codebuf *);
extern void init16(struct codebuf *);
extern unsigned int xcode(struct codebuf *);
/* vartab tracks the variable size codes. For each size code the
* initialization routine, code size, largest code, and assembly state
* information is recorded.
*
* To advance to next sized code, read codes at current size while not
* at the original state, then call init routine for next size (and
* record initial state info).
*/
struct codesize vartab [] = {
{ init9, 9, 0x1ffL, 0 },
{ init10, 10, 0x3ffL, 0 },
{ init11, 11, 0x7ffL, 0 },
{ init12, 12, 0xfffL, 0 },
{ init13, 13, 0x1fffL, 0 },
{ init14, 14, 0x3fffL, 0 },
{ init15, 15, 0x7fffL, 0 },
{ init16, 16, 0x10000L, 0 }
};
/* Record current entry in vartab.
*/
int curvartab = 0;
#ifdef DEBUG
long bytes_out = 0;
#endif
/* buf is the input file buffer. Also used to store the initial help
* message you get with the -H option.
*/
unsigned char buf[MAXBUF] = "\
u16 - 16 bit LZW uncompress for the IBM PC\n\
u16 [-H] [files...]\n\
\n\
-H\tPrint this message and exit.\n\
\n\
Uncompresses each input file and writes result to stdout. With no\n\
input file specified, reads stdin. Probably requires 270-280K of free\n\
memory to run.\n\
\n\
Written for the IBM PC by tahorsley@ssd.harris.com (Tom Horsley).\n\
\n\
NOTE: this is kind of like zcat, but it does not try to stick any .Z's\n\
on the ends of file names.\n"
;
/* Number of bytes of file data resident in buf.
*/
int bufsize = 0;
/* Address of first byte in buffer past end of file
* (only set when the last buffer is read).
*/
char * eofmark = NULL;
/* Address of byte near end of buffer (used to determine
* when to read additional data).
*/
char * endbuf;
/* Flag data read from file.
*/
int block_compress;
int maxbits;
/* State variables controlling decompression
*/
#define FIRST 257 /* first free entry */
#define CLEAR 256 /* table clear output code */
int clear_flg = 0;
long free_ent = 0;
long maxcode;
#define FAR far
char FAR * de_stack;
/* tabprefix is the only real fly in the ointment, it needs to be a
* huge array, but could probably be changed to a couple of far arrays
* with the resulting additional complications in the tab_prefixof()
* macro.
*/
unsigned int huge * tabprefix;
unsigned char FAR * tabsuffix;
#define tab_prefixof(_i) tabprefix[_i]
#define tab_suffixof(_i) tabsuffix[_i]
long maxmaxcode = 65536L;
/* ReadBuf reads some data into the buffer following the data already
* in the buffer (if any). It tries to fill it up, and sets the end of
* file flag if it can't.
*/
void
ReadBuf()
{
int cursize;
int want;
while ((eofmark == NULL) && ((want = MAXBUF - bufsize) > 0)) {
cursize = read(fileno(stdin), &buf[bufsize], want);
if (cursize < 0) {
perror("u16");
exit(1);
} else if (cursize == 0) {
eofmark = &buf[bufsize];
} else {
bufsize += cursize;
}
}
if (eofmark == NULL) {
endbuf = &buf[bufsize] - 32;
} else {
endbuf = eofmark;
}
}
/* getcode deals with buffer filling, switching code size, and calling
* the assembler unpacking routines.
*/
long int
getcode()
{
int leftover;
if (cb.bufp >= endbuf) {
if (eofmark != NULL) {
return(-1L);
} else {
/* move the un-read data to the top of the buffer, then read
* some additional data.
*/
leftover = &buf[bufsize] - cb.bufp;
memmove(&buf[0], cb.bufp, leftover);
cb.bufp = &buf[0];
bufsize = leftover;
ReadBuf();
}
}
if (clear_flg > 0 || free_ent > maxcode) {
/* If the next entry will be too big for the current code, or we
* have recieved a clear code then flush the current size code
* and advance to next size.
*/
while (cb.codep != vartab[curvartab].origp) xcode(&cb);
if (cb.bufp >= endbuf) return(-1L);
if (clear_flg > 0) {
curvartab = 0;
clear_flg = 0;
} else {
++curvartab;
if (curvartab > (16 - 9)) {
#ifdef DEBUG
fputs("Attempt to overflow 16 bit codes.\n",stderr);
#endif
curvartab = 16 - 9;
}
}
(*vartab[curvartab].initp)(&cb);
vartab[curvartab].origp = cb.codep;
maxcode = vartab[curvartab].maxcode;
#ifdef DEBUG
fprintf(stderr,
"switching to %d bit codes, bytes_out = %ld, free_ent = %ld\n",
vartab[curvartab].n_bits,bytes_out, free_ent);
#endif
}
return (long)(xcode(&cb));
}
/* Decompress stdin to stdout. This routine adapts to the codes in
* the file building the "string" table on-the-fly; requiring no table
* to be stored in the compressed file.
*
* This routine taken practically verbatim from the net compress
* program:
*
* $Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $
*
* compress.c - File compression ala IEEE Computer, June 1984.
*
* Authors:
* Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
* Jim McKie (decvax!mcvax!jim)
* Steve Davies (decvax!vax135!petsd!peora!srd)
* Ken Turkowski (decvax!decwrl!turtlevax!ken)
* James A. Woods (decvax!ihnp4!ames!jaw)
* Joe Orost (decvax!vax135!petsd!joe)
*/
int
decompress() {
register unsigned char FAR * stackp;
register int finchar;
register long code, oldcode, incode;
#ifdef DEBUG
long stacksize = 0;
#endif
/* No buffering on stdin, we do all our own buffering.
*/
setvbuf(stdin, NULL, _IONBF, 0);
/* Operate in the binary file domain, don't want DOS screwing
* around with '\r''s.
*/
setmode(fileno(stdin), O_BINARY);
setmode(fileno(stdout), O_BINARY);
/* Read the iniital buffer worth of data and check magic numbers
* and flags.
*/
ReadBuf();
if (bufsize < 3) {
fputs("u16: Missing file header.\n",stderr);
return 1;
}
if (memcmp(buf,magic_header,2) != 0) {
fputs("u16: Bad magic number.\n",stderr);
return 1;
}
block_compress = buf[2] & BLOCK_MASK;
maxbits = buf[2] & BIT_MASK;
if (maxbits > 16) {
fputs("u16: Cannot decompress, compressed with more than 16 bits.\n",
stderr);
return 1;
}
/* Initialize the xcode routine to start reading 9 bit codes at the
* third byte of the initial buffer.
*/
cb.bufp = &buf[3];
init9(&cb);
vartab[0].origp = cb.codep;
curvartab = 0;
/*
* initialize the first 256 entries in the table.
*/
maxcode = vartab[0].maxcode;
for ( code = 255; code >= 0; code-- ) {
tab_prefixof(code) = 0;
tab_suffixof(code) = (unsigned char)code;
}
free_ent = ((block_compress) ? FIRST : 256 );
finchar = oldcode = getcode();
if(oldcode == -1) /* EOF already? */
return; /* Get out of here */
putchar((char)finchar ); /* first code must be 8 bits = char */
#ifdef DEBUG
++bytes_out;
#endif
if(ferror(stdout)) { /* Crash if can't write */
perror("u16");
exit(1);
}
stackp = de_stack;
while ( (code = getcode()) > -1 ) {
if ( (code == CLEAR) && block_compress ) {
#ifdef DEBUG
fprintf(stderr,
"Input CLEAR code bytes_out = %ld, free_ent = %ld\n",
bytes_out, free_ent);
#endif
for ( code = 255; code >= 0; code-- )
tab_prefixof(code) = 0;
clear_flg = 1;
free_ent = FIRST - 1;
if ( (code = getcode ()) == -1 ) /* O, untimely death! */
break;
}
incode = code;
/* Special case for KwKwK string.
*/
if ( code >= free_ent ) {
#ifdef DEBUG
++stacksize;
if (stacksize >= 65536L) {
fputs("stacksize overflow.\n",stderr);
exit(1);
}
#endif
*stackp++ = finchar;
code = oldcode;
}
/* Generate output characters in reverse order
*/
while ( code >= 256 ) {
#ifdef DEBUG
++stacksize;
if (stacksize >= 65536L) {
fputs("stacksize overflow.\n",stderr);
exit(1);
}
if ((code < 0) || (code >= 65536L)) {
fprintf(stderr,"bad subscript, code = %ld\n",code);
}
#endif
*stackp++ = tab_suffixof(code);
code = tab_prefixof(code);
}
#ifdef DEBUG
++stacksize;
if (stacksize >= 65536L) {
fputs("stacksize overflow.\n",stderr);
exit(1);
}
if ((code < 0) || (code >= 65536L)) {
fprintf(stderr,"bad subscript, code = %ld\n",code);
}
#endif
*stackp++ = finchar = tab_suffixof(code);
#ifdef DEBUG
if (stacksize > 65536L) {
fprintf(stderr,"stacksize reached %ld\n",stacksize);
}
#endif
/* And put them out in forward order
*/
do {
putchar ( *--stackp );
#ifdef DEBUG
++bytes_out;
--stacksize;
#endif
} while ( stackp > de_stack );
#ifdef DEBUG
if (stacksize != 0) {
fprintf(stderr,"stacksize = %ld, not empty!\n",stacksize);
}
#endif
/* Generate the new entry.
*/
if ( (code=free_ent) < maxmaxcode ) {
#ifdef DEBUG
if ((code < 0) || (code >= 65536L)) {
fprintf(stderr,"bad subscript, code = %ld\n",code);
}
#endif
tab_prefixof(code) = (unsigned short)oldcode;
tab_suffixof(code) = finchar;
free_ent = code+1;
}
/* Remember previous code.
*/
oldcode = incode;
}
fflush( stdout );
if(ferror(stdout)) {
perror("u16");
return 1;
}
return 0;
}
/* 16 bit uncompress optimized for 8086 architecture. The getcode
* routine is in 8086 assembler optimized for extracting the variable
* sized code rapidly.
*/
void
main(argc, argv)
int argc;
char * argv[];
{
int errors = 0;
/* Process options (only supports -H)
*/
--argc;
++argv;
while ((argc > 0) && (argv[0][0] == '-')) {
if (argv[0][1] == 'H') {
fputs(buf,stderr);
exit(0);
} else {
fputs("u16: unrecognized option ",stderr);
fputs(argv[0],stderr);
fputs("\n",stderr);
fputs("usage: u16 [-H] [files...]\n",stderr);
exit(1);
}
--argc;
++argv;
}
/* Allocate a large buffer for stdout (speeds up the program by a
* fair percentage).
*/
setvbuf(stdout, NULL, _IOFBF, MAXBUF);
/* Allocate space for tables
*/
de_stack = (unsigned char FAR *)halloc(65536L, sizeof(unsigned char));
tabprefix = (unsigned int huge *)halloc(65536L, sizeof(unsigned int));
tabsuffix = (unsigned char FAR *)halloc(65536L, sizeof(unsigned char));
if ((de_stack == NULL) || (tabprefix == NULL) || (tabsuffix == NULL)) {
fputs("u16: out of memory.\n",stderr);
exit(1);
}
if (argc == 0) {
/* Just decompress stdin
*/
if (decompress()) {
++errors;
fputs("u16: error decompressing stdin.\n",stderr);
}
} else {
while (argc > 0) {
if (freopen(argv[0], "r", stdin) == NULL) {
fputs("u16: cannot read ",stderr);
fputs(argv[0],stderr);
fputs("\n",stderr);
++errors;
} else {
if (decompress()) {
fputs("u16: error in ",stderr);
fputs(argv[0],stderr);
fputs("\n",stderr);
++errors;
}
fclose(stdin);
}
--argc;
++argv;
}
}
#ifdef DEBUG
fprintf(stderr,"Total bytes out = %ld\n",bytes_out);
#endif
exit(errors);
}